﻿// <copyright file="IObjectExtension.cs" company="Codeplex project Eco.Contrib"> 
// The MIT License (MIT) 
// </copyright> 
// <author>Peter Buchmann</author> 

namespace Eco.Contrib
{
    using Eco.ObjectImplementation;
    using Eco.ObjectRepresentation;
    using Eco.Services;

    /// <summary>
    /// IObjectExtension: Collection of extension methods for IObjects
    /// </summary>
    public static class IObjectExtension
    {
        /// <summary>
        /// Copies all attributes from SourceObject to TargetObject that have the same name in both classes.
        /// It is not necessary that both objects have the same type.
        /// </summary>
        /// <param name="targetObject">The target object.</param>
        /// <param name="sourceObject">The source object.</param>
        public static void CopyAttributesByName(this IElement targetObject, IEcoObject sourceObject)
        {
            if (targetObject == null)
            {
                throw new EcoContribException("Parameter is null");
            }

            (targetObject.AsObject as IEcoObject).CopyAttributesByName(sourceObject);
        }

        /// <summary>
        /// Copies all attributes from SourceObject to TargetObject that have the same name in both classes.
        /// Associations are only copied when the name of the association end is added in the string list associationNames.
        /// It is not necessary that both objects have the same type.
        /// </summary>
        /// <param name="targetObject">The target object.</param>
        /// <param name="sourceObject">The source object.</param>
        /// <param name="associationNames">The association names.</param>
        public static void CopyAttributesByName(this IElement targetObject, IEcoObject sourceObject, string[] associationNames)
        {
            if (targetObject == null)
            {
                throw new EcoContribException("Parameter is null");
            }

            (targetObject.AsObject as IEcoObject).CopyAttributesByName(sourceObject, associationNames);
        }

        /// <summary>
        /// Copies all attributes from SourceObject to TargetObject that have the same name in both classes.
        /// Associations are only copied when the name of the association end is added in the string list associationNames.
        /// It is not necessary that both objects have the same type.
        /// </summary>
        /// <param name="targetObject">The target object.</param>
        /// <param name="sourceObject">The source object.</param>
        /// <param name="associationNames">The association names.</param>
        public static void CopyAttributesByName(this IElement targetObject, IElement sourceObject, string[] associationNames)
        {
            if (targetObject == null)
            {
                throw new EcoContribException("Parameter is null");
            }

            (targetObject.AsObject as IEcoObject).CopyAttributesByName(sourceObject as IEcoObject, associationNames);
        }

        /// <summary>
        /// Copies all attributes from SourceObject to TargetObject that have the same name in both classes.
        /// Associations are only copied when the name of the association end is in commaSeparatedAssociationNames.
        /// It is not necessary that both objects have the same type.
        /// </summary>
        /// <param name="targetObject">The target object.</param>
        /// <param name="sourceObject">The source object.</param>
        /// <param name="commaSeparatedAssociationNames">The comma Separated association names.</param>
        public static void CopyAttributesByName(this IElement targetObject, IEcoObject sourceObject, string commaSeparatedAssociationNames)
        {
            if (targetObject == null)
            {
                throw new EcoContribException("Parameter is null");
            }

            if (commaSeparatedAssociationNames == null)
            {
                throw new EcoContribException("Parameter is null");
            }

            (targetObject.AsObject as IEcoObject).CopyAttributesByName(sourceObject, commaSeparatedAssociationNames.Split(','));
        }

        /// <summary>
        /// Copies all attributes from SourceObject to TargetObject that have the same name in both classes.
        /// Associations are only copied when the name of the association end is in commaSeparatedAssociationNames.
        /// It is not necessary that both objects have the same type.
        /// </summary>
        /// <param name="targetObject">The target object.</param>
        /// <param name="sourceObject">The source object.</param>
        /// <param name="commaSeparatedAssociationNames">The comma Separated association names.</param>
        public static void CopyAttributesByName(this IElement targetObject, IObject sourceObject, string commaSeparatedAssociationNames)
        {
            if (targetObject == null)
            {
                throw new EcoContribException("Parameter is null");
            }

            if (commaSeparatedAssociationNames == null)
            {
                throw new EcoContribException("Parameter is null");
            }

            (targetObject.AsObject as IEcoObject).CopyAttributesByName(sourceObject, commaSeparatedAssociationNames.Split(','));
        }

        /// <summary>
        /// Save this only object via the current PersistenceService.
        /// </summary>
        /// <param name="ecoObject">The objekt.</param>
        public static void Save(this IObject ecoObject)
        {
            if (ecoObject != null)
            {
                ecoObject.ServiceProvider.GetEcoService<IPersistenceService>().UpdateDatabase(ecoObject);
            }
        }

        /// <summary>
        /// Save this list of objects via the current PersistenceService.
        /// </summary>
        /// <param name="objectList">The objekt list.</param>
        public static void Save(this IObjectList objectList)
        {
            if ((objectList != null) && (objectList.Count > 0))
            {
                objectList[0].ServiceProvider.GetEcoService<IPersistenceService>().UpdateDatabaseWithList(objectList);
            }
        }

        /// <summary>
        /// Gets the fetched value of a attribute of a object
        /// </summary>
        /// <param name="element">The objekt.</param>
        /// <param name="attribute">The attribute.</param>
        /// <returns>Fetched value of a attribute of a object</returns>
        public static object FetchedValue(this IElement element, string attribute)
        {
            if (element == null)
            {
                throw new EcoContribException("Parameter is null");
            }

            return (element.AsObject as IEcoObject).FetchedValue(attribute);
        }

        /// <summary>
        /// Gets the fetched value of a attribute of a object by LoopbackIndex
        /// </summary>
        /// <param name="featuredObject">The objekt.</param>
        /// <param name="loopbackIndex">Index of the loopback.</param>
        /// <returns>fetched value of given attribute</returns>
        public static object FetchedValue(this IFeatured featuredObject, int loopbackIndex)
        {
            if (featuredObject == null)
            {
                throw new EcoContribException("Parameter is null");
            }

            return featuredObject.Properties[loopbackIndex].AsObject;
        }

        /// <summary>
        /// True, if relevant Attribute was changed since it was fetched.
        /// </summary>
        /// <param name="featuredObject">The object.</param>
        /// <param name="loopbackIndex">Index of the loopback.</param>
        /// <returns><c>true</c> if attribute value was changed since fetch, <c>false</c> otherwise</returns>
        public static bool AttributeValueChanged(this IFeatured featuredObject, int loopbackIndex)
        {
            if (featuredObject == null)
            {
                throw new EcoContribException("Parameter is null");
            }

            return featuredObject.FetchedValue(loopbackIndex) != featuredObject.Properties[loopbackIndex].AsObject;
        }

        /// <summary>
        /// True, if relevant Attribute was changed since it was fetched.
        /// </summary>
        /// <param name="featuredObject">The objekt.</param>
        /// <param name="attribute">The attribute.</param>
        /// <returns><c>true</c> if attribute value was changed since fetch, <c>false</c> otherwise</returns>
        public static bool AttributeValueChanged(this IFeatured featuredObject, string attribute)
        {
            if (featuredObject == null)
            {
                throw new EcoContribException("Parameter is null");
            }

            return featuredObject.FetchedValue(attribute) != featuredObject.Properties[attribute].AsObject;
        }

        /// <summary>
        /// Ensures that all objects are loaded.
        /// </summary>
        /// <typeparam name="T">T must be a IEcoObject</typeparam>
        /// <param name="ecoList">The eco list.</param>
        public static void EnsureObjects<T>(this IEcoList<T> ecoList) where T : class, IEcoObject
        {
            if (ecoList == null)
            {
                throw new EcoContribException("Parameter is null");
            }

            ecoList.AsIObjectList.EnsureObjects();
        }

        /// <summary>
        /// True, if any attribute of the object was changed, this means the object has to be saved.
        /// </summary>
        /// <param name="ecoObject">The objekt.</param>
        /// <returns>
        ///   <c>true</c> if the specified objekt is dirty; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsDirty(this IObject ecoObject)
        {
            if (ecoObject == null)
            {
                throw new EcoContribException("Parameter is null");
            }
            
            return ecoObject.ServiceProvider.GetEcoService<IStateService>().IsDirty(ecoObject);
        }
    }
}
